package userFileModuleApi

import (
	"KumquatDrivesServices/StorageEngine"
	"KumquatDrivesServices/common/res"
	"KumquatDrivesServices/enums"
	"KumquatDrivesServices/global"
	"KumquatDrivesServices/model"
	"KumquatDrivesServices/utils"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"golang.org/x/sync/errgroup"
	"path/filepath"
)

type mergeFileRequest struct {
	FileId   string                `json:"fileId" binding:"required"`
	FileName string                `json:"fileName" binding:"required"`
	FileMd5  string                `json:"fileMd5" binding:"required"`
	FilePid  model.SnowflakeIdType `json:"filePid" binding:"required"`
}

func (UserFileModuleApi) MergeFile(c *gin.Context) {
	var req mergeFileRequest
	if err := c.ShouldBind(&req); err != nil {
		logrus.Errorf("bind err:%v", err)
		res.FailWithCode(res.PARAM_ERR, c)
		return
	}
	userId := utils.GetUserId(c)
	uploadId := StorageEngine.EngineID(req.FileId)
	tmpFileSize, getTempFileSizeErr := uploadId.GetTempFileSize(userId)
	if getTempFileSizeErr != nil {
		if errors.Is(getTempFileSizeErr, StorageEngine.InvalidEngineIDErr) {
			res.FailWithCode(res.UPLOAD_ID_INVALID, c)
			return
		}
		logrus.Errorf("get temp file size err:%v", getTempFileSizeErr)
		res.FailWithCode(res.PARAM_ERR, c)
		return
	}
	var userModel model.UserModel
	userModel.ID = userId
	remainingCapacity, getCapacityErr := userModel.GetUserRemainingCapacity()
	if getCapacityErr != nil {
		logrus.Errorf("get user remaining capacity err:%v", getCapacityErr)
		res.FailWithCode(res.LOGIN_EXPIRED, c)
		return
	}
	if tmpFileSize > remainingCapacity {
		res.FailWithCode(res.LACK_OF_SPACE, c)
		return
	}
	MergeFilePath, fileSize, mergeFileErr := StorageEngine.Engine.MergeTempFiles(uploadId, userId, req.FileMd5+filepath.Ext(req.FileName), tmpFileSize)
	if mergeFileErr != nil {
		logrus.Errorf("merge file err:%v", mergeFileErr)
		res.FailWithCode(res.UPLOAD_FAIL, c)
		return
	}
	fileTypeEnums := enums.GetFileTypeBySuffix(req.FileName)
	fileName, autoRenameErr := autoRename(req.FilePid, userId, req.FileName)
	if autoRenameErr != nil {
		logrus.Errorf("rename file err:%v", autoRenameErr)
		res.FailWithCode(res.UPLOAD_FAIL, c)
		return
	}
	coverImagePath := ""
	switch fileTypeEnums.Category {
	case enums.VIDEO:
		group := new(errgroup.Group)
		group.Go(func() error {
			ImagePath, err := StorageEngine.Engine.CreateVideoThumbnail(MergeFilePath)
			if err != nil {
				logrus.Errorf("create video thumbnail err:%v", err)
				return err
			}
			coverImagePath = ImagePath
			return nil
		})
		group.Go(func() error {
			if err := StorageEngine.Engine.CutFileForVideo(MergeFilePath); err != nil {
				logrus.Errorf("cut file err:%v", err)
				return err
			}
			return nil
		})
		if err := group.Wait(); err != nil {
			logrus.Errorf("wait err:%v", err)
			if err = StorageEngine.Engine.RemoveMergeFile(MergeFilePath); err != nil {
				logrus.Errorf("remove merge file err:%v", err)
			}
			res.FailWithCode(res.UPLOAD_FAIL, c)
			return
		}
	case enums.IMAGE:
		ImagePath, err := StorageEngine.Engine.GenerateThumbnail(MergeFilePath)
		if err != nil {
			logrus.Errorf("generate thumbnail err:%v", err)
			if err = StorageEngine.Engine.RemoveMergeFile(MergeFilePath); err != nil {
				logrus.Errorf("remove merge file err:%v", err)
			}
			res.FailWithCode(res.UPLOAD_FAIL, c)
			return
		}
		coverImagePath = ImagePath
	default:
	}
	if coverImagePath != "" {
		coverImagePath = encryptFilePath(userId, coverImagePath)
	}
	dbTransaction := global.DB.Begin()
	fileModel := model.FileModel{
		UserId:    userId,
		FilePid:   req.FilePid,
		FileName:  fileName,
		FileMd5:   req.FileMd5,
		FileSize:  fileSize,
		FileType:  uint8(fileTypeEnums.Category),
		IsFolder:  enums.File,
		FilePath:  MergeFilePath,
		FileCover: coverImagePath,
		DelFlag:   enums.Normal,
	}
	if createErr := dbTransaction.Create(&fileModel).Error; createErr != nil {
		logrus.Errorf("create file err:%v", createErr)
		dbTransaction.Rollback()
		if err := StorageEngine.Engine.RemoveMergeFile(MergeFilePath); err != nil {
			logrus.Errorf("remove merge file err:%v", err)
		}
		res.FailWithCode(res.UPLOAD_FAIL, c)
		return
	}
	if err := userModel.UpdateUserCapacity(tmpFileSize, enums.AddUserCapacity); err != nil {
		logrus.Errorf("update user capacity err:%v", err)
		res.FailWithCode(res.UPLOAD_FAIL, c)
		return
	}
	if err := dbTransaction.Commit().Error; err != nil {
		dbTransaction.Rollback()
		logrus.Errorf("commit err:%v", err)
		if err = StorageEngine.Engine.RemoveMergeFile(MergeFilePath); err != nil {
			logrus.Errorf("remove merge file err:%v", err)
		}
		res.FailWithCode(res.UPLOAD_FAIL, c)
		return
	}
	res.OkWithCode(res.UPLOAD_COMPLETE, c)
	if err := uploadId.DeleteTempFileSize(userId); err != nil {
		logrus.Errorf("delete temp file size err:%v", err)
	}
}
